package com.gr.staffpm;

import java.io.File;
import java.io.Serializable;
import java.util.concurrent.TimeUnit;

import org.apache.wicket.Page;
import org.apache.wicket.ResourceReference;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.settings.IExceptionSettings;
import org.apache.wicket.spring.injection.annot.SpringComponentInjector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wicketstuff.annotation.scan.AnnotatedMountScanner;

import com.atlassian.plugin.DefaultModuleDescriptorFactory;
import com.atlassian.plugin.hostcontainer.DefaultHostContainer;
import com.atlassian.plugin.main.AtlassianPlugins;
import com.atlassian.plugin.main.PluginsConfiguration;
import com.atlassian.plugin.main.PluginsConfigurationBuilder;
import com.atlassian.plugin.osgi.container.PackageScannerConfiguration;
import com.atlassian.plugin.osgi.container.impl.DefaultPackageScannerConfiguration;
import com.atlassian.plugin.osgi.hostcomponents.ComponentRegistrar;
import com.atlassian.plugin.osgi.hostcomponents.HostComponentProvider;
import com.gr.staffpm.css.CssScope;
import com.gr.staffpm.images.ImageScope;
import com.gr.staffpm.js.StaffPMJSScope;
import com.gr.staffpm.pages.dashboard.Dashboard;
import com.gr.staffpm.pages.error.AccessDeniedPage;
import com.gr.staffpm.pages.error.ExpiredPage;
import com.gr.staffpm.pages.error.InternalErrorPage;
import com.gr.staffpm.pages.error.UnauthorizedPage;
import com.gr.staffpm.pages.login.Login;
import com.gr.staffpm.plugins.DefaultPluginService;
import com.gr.staffpm.plugins.PluginService;
import com.gr.staffpm.plugins.modules.OnStartModuleDescriptor;
import com.gr.staffpm.properties.PropertiesController;
import com.gr.staffpm.security.AnnotationsShiroAuthorizationStrategy;
import com.gr.staffpm.security.ShiroUnauthorizedComponentListener;


public class StaffPMApplication extends WebApplication implements Serializable {

    private static final long serialVersionUID = 1L;
    private boolean isInitialized = false;
    private final Logger log = LoggerFactory.getLogger(getClass());
    private final DefaultPluginService pluginService = new DefaultPluginService();
    private AtlassianPlugins plugins;

    @Override
    protected void init() {
        if (!isInitialized) {

            super.init();
            getMarkupSettings().setStripWicketTags(true);
            setListeners();
            setupShiroSecurity();

            mountResources();
            setErrorPages();

            // Read properties file.
            log.info("Reading properties...");
            PropertiesController.getInstance();

            //setupPluginFramework();
            //runOnStartPlugins();

            isInitialized = true;
        }
    }

    public void runOnStartPlugins() {
        for (Runnable runnable : plugins.getPluginAccessor().getEnabledModulesByClass(Runnable.class)) {
            runnable.run();
        }
    }

    public void setupPluginFramework() {

        // Determine which packages to expose to plugins
        PackageScannerConfiguration scannerConfig = new DefaultPackageScannerConfiguration();
        ((DefaultPackageScannerConfiguration) scannerConfig).setServletContext(getServletContext());
        scannerConfig.getPackageIncludes().add("com.gr.staffpm.feedback*");
        scannerConfig.getPackageIncludes().add("com.gr.staffpm.notes*");
        scannerConfig.getPackageIncludes().add("com.gr.staffpm.projects*");
        scannerConfig.getPackageIncludes().add("com.gr.staffpm.security*");
        scannerConfig.getPackageIncludes().add("com.gr.staffpm.tasks*");

        // Determine which module descriptors, or extension points, to expose.
        DefaultModuleDescriptorFactory modules = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
        modules.addModuleDescriptor("on-start", OnStartModuleDescriptor.class);

        // Determine which service objects to expose to plugins
        HostComponentProvider host = new HostComponentProvider() {

            @Override
            public void provide(ComponentRegistrar reg) {
                reg.register(PluginService.class).forInstance(pluginService);
            }
        };

        File pluginDirectory = new File(PropertiesController.getInstance().getProperty("plugin.directory"));
        log.info("Plugin Directory: " + pluginDirectory.getAbsolutePath() + " exists: " + pluginDirectory.exists());

        // Construct the configuration
        PluginsConfiguration config =
                new PluginsConfigurationBuilder().pluginDirectory(pluginDirectory).packageScannerConfiguration(scannerConfig).hotDeployPollingFrequency(1, TimeUnit.HOURS).hostComponentProvider(
                        host).moduleDescriptorFactory(modules).build();

        // Start the plugin framework
        plugins = new AtlassianPlugins(config);
        plugins.start();

    }

    private void setupShiroSecurity() {
        AnnotationsShiroAuthorizationStrategy authz = new AnnotationsShiroAuthorizationStrategy();
        getSecuritySettings().setAuthorizationStrategy(authz);
        getSecuritySettings().setUnauthorizedComponentInstantiationListener(new ShiroUnauthorizedComponentListener(Login.class, UnauthorizedPage.class, authz));
    }

    private void setListeners() {
        addComponentInstantiationListener(new SpringComponentInjector(this));
    }

    @Override
    public Class<? extends Page> getHomePage() {
        return Dashboard.class;
    }

    private void setErrorPages() {
        getApplicationSettings().setPageExpiredErrorPage(ExpiredPage.class);
        getApplicationSettings().setAccessDeniedPage(AccessDeniedPage.class);
        getApplicationSettings().setInternalErrorPage(InternalErrorPage.class);
        // show internal error page rather than default developer page
        getExceptionSettings().setUnexpectedExceptionDisplay(IExceptionSettings.SHOW_INTERNAL_ERROR_PAGE);
    }

    private void mountResources() {
        new AnnotatedMountScanner().scanPackage("com.gr.staffpm.pages").mount(this);

        mountSharedResource("favicon.ico", new ResourceReference(ImageScope.class, "favicon.ico").getSharedResourceKey());
        mountSharedResource("/css/StaffPM.css", new ResourceReference(CssScope.class, "StaffPM.css").getSharedResourceKey());
        mountSharedResource("/css/pages.css", new ResourceReference(CssScope.class, "pages.css").getSharedResourceKey());
        mountSharedResource("utils.js", new ResourceReference(StaffPMJSScope.class, "utils.js").getSharedResourceKey());
        mountSharedResource("/images/loading.gif", new ResourceReference(ImageScope.class, "large-loading.gif").getSharedResourceKey());
        mountSharedResource("/images/me_repeat_x.png", new ResourceReference(ImageScope.class, "me_repeat_x.png").getSharedResourceKey());
        mountSharedResource("/images/me_assets.png", new ResourceReference(ImageScope.class, "me_assets.png").getSharedResourceKey());
        mountSharedResource("/images/me_controls.png", new ResourceReference(ImageScope.class, "me_controls.png").getSharedResourceKey());
        mountSharedResource("/images/Clientlogo.bmp", new ResourceReference(ImageScope.class, "Clientlogo.bmp").getSharedResourceKey());
        mountSharedResource("/images/seperator.gif", new ResourceReference(ImageScope.class, "seperator.gif").getSharedResourceKey());
        mountSharedResource("/images/hover.gif", new ResourceReference(ImageScope.class, "hover.gif").getSharedResourceKey());
        mountSharedResource("/images/sub_sep.gif", new ResourceReference(ImageScope.class, "sub_sep.gif").getSharedResourceKey());
        mountSharedResource("/images/hover_sub.gif", new ResourceReference(ImageScope.class, "hover_sub.gif").getSharedResourceKey());
        mountSharedResource("/images/dropdowns.gif", new ResourceReference(ImageScope.class, "dropdowns.gif").getSharedResourceKey());
        mountSharedResource("/images/cog.gif", new ResourceReference(ImageScope.class, "cog.gif").getSharedResourceKey());
        mountSharedResource("/images/combined_v19.png", new ResourceReference(ImageScope.class, "combined_v19.png").getSharedResourceKey());
        mountSharedResource("/images/ui-bg_glass.png", new ResourceReference(ImageScope.class, "ui-bg_glass.png").getSharedResourceKey());
        mountSharedResource("/images/header-separator.png", new ResourceReference(ImageScope.class, "header-separator.png").getSharedResourceKey());
        mountSharedResource("/images/mod_header_bg.png", new ResourceReference(ImageScope.class, "mod_header_bg.png").getSharedResourceKey());
        mountSharedResource("/images/menu_indicator_for_light_backgrounds.gif", new ResourceReference(ImageScope.class, "menu_indicator_for_light_backgrounds.gif").getSharedResourceKey());
        mountSharedResource("/images/announcements.png", new ResourceReference(ImageScope.class, "announcements.png").getSharedResourceKey());
        mountSharedResource("/images/announcements_selected.png", new ResourceReference(ImageScope.class, "announcements_selected.png").getSharedResourceKey());
        mountSharedResource("/images/error_bg.png", new ResourceReference(ImageScope.class, "error_bg.png").getSharedResourceKey());
        mountSharedResource("/images/aui-icon-forms.gif", new ResourceReference(ImageScope.class, "aui-icon-forms.gif").getSharedResourceKey());
        mountSharedResource("/images/icons/add_user.png", new ResourceReference(ImageScope.class, "icons/add_user.png").getSharedResourceKey());
    }

}
